package com.bnzj.cloud.gateway.webflux;

import com.bnzj.cloud.business.core.persistence.entity.SysResource;
import com.bnzj.cloud.business.core.service.SysResourceService;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @ClassName CustomAccessDecisionRuleWebflux
 * @Description 已登录用户是否有权限访问某个资源
 * @Author
 * @Date 2020/2/19
 * @Version V1.0
 **/
@Slf4j
@Component("customReactiveAuthorizationManager")
public class CustomAccessDecisionRuleWebflux implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Autowired
    private SysResourceService sysResourceService;

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext object) {
        String uri = object.getExchange().getRequest().getPath().value();
        String requestMethod = object.getExchange().getRequest().getMethodValue();
        return authentication
                .map( a-> new AuthorizationDecision(check(a, uri, requestMethod)))
                .defaultIfEmpty(new AuthorizationDecision(false));
    }


    private boolean check(Authentication authentication, String uri, String methodType){
        boolean result = true;
        AntPathMatcher apm = new AntPathMatcher();
        List<SysResource> allResource = sysResourceService.findAll();
        boolean isResourceSecured = allResource.stream()
                .anyMatch(resource->apm.match(resource.getUrl(), uri));
        String userName = null;
        if(authentication instanceof JwtAuthenticationToken){
            userName = ((Jwt)authentication.getCredentials()).getClaims().get("user_name").toString();
        }else if(authentication instanceof UsernamePasswordAuthenticationToken){
            userName = authentication.getPrincipal().toString();
        }
        if(isResourceSecured){
            List<SysResource> userResources = sysResourceService.findAllByUserAccount(userName);
            result = userResources.stream()
                    .anyMatch(resource->apm.match(resource.getUrl(), uri));
            log.info("用户({})请求：{}, 该URI需要进行权限校验，用户{}访问权限", userName, uri, result ? "具有" : "没有");
        }else {
            log.info("用户({})请求：{}, 该URI不需要进行权限校验", userName, uri);
        }
        return result;
    }
}
